#include "AT_CmdBase.h"



#define MSGQUEUE_ISFULL       (at_cmd_maininfo.msgqueue_readindex == (at_cmd_maininfo.msgqueue_writeindex + 1)%AT_CMD_QUEUE_MAX_SIZE ? 1 : 0)
#define MSGQUEUE_ISEMPTY      (at_cmd_maininfo.msgqueue_readindex == at_cmd_maininfo.msgqueue_writeindex)
#define MSGQUEUE_INDEX_INC(i) (i = (i + 1) % AT_CMD_QUEUE_MAX_SIZE) 


typedef enum AT_CMD_MSG_TYPE_t
{
     AT_CMD_MSG_TYPE_CONFIRMREPLY = 1,   //确定返回值的消息类型
     AT_CMD_MSG_TYPE_UNCONFIRMREPLY = 2, //不确定返回值的消息类型
     AT_CMD_MSG_TYPE_MAX = 0xffffffff,   
}AT_CMD_MSG_TYPE;

/*
每个AT命令的相关信息结构体
*/
typedef struct AT_CMD_Element_t
{
   char *senddata;          //命令字符
   char *responseok;        //正确响应字符
   char *responseerr;       //错误响应字符
   AT_ResponseCallback cb;  //命令执行回调
   int mstimeout;           //命令接收超时时间
   AT_CMD_MSG_TYPE msgtype; //命令类型
   void *data;              //用户自定义数据，回调时传回
}AT_CMD_Element;

static AT_CMD_Element at_cmd_msgqueue[AT_CMD_QUEUE_MAX_SIZE];

 

/*
AT命令执行主要信息
*/
typedef struct AT_CMD_MainInfo_t
{
   AT_SendData send;
   AT_RevData  rev;
   AT_GetCurTicks getticks;
   int msgqueue_readindex;
   int msgqueue_writeindex;
   int msgqueue_handleindex;
   char Revbuf[AT_CMD_REVBUF_MAX_SIZE]; 
   int  RevbufValidlen;  
   long cmdTimeoutticks; //开始处理命令的时间
}AT_CMD_MainInfo;

static AT_CMD_MainInfo at_cmd_maininfo;

static char *AT_CmdBaseDeepcopy(char *src)
{
   char *ptemp = (char *)malloc(strlen(src) + 1);
   if(ptemp != NULL)
        memcpy(ptemp, src, strlen(src));
   return ptemp;
}

static void AT_CmdBaseClearElement(int index)
{
    if(index >= AT_CMD_QUEUE_MAX_SIZE)
       return ;
    AT_CMD_Element *curWriteElement = &at_cmd_msgqueue[index];
    free(curWriteElement->senddata);
    free(curWriteElement->responseerr);
    free(curWriteElement->responseok);
    curWriteElement->cb = NULL;
    curWriteElement->mstimeout = 0;
    curWriteElement->senddata = NULL;
    curWriteElement->responseerr = NULL;
    curWriteElement->responseok = NULL;
    curWriteElement->msgtype = AT_CMD_MSG_TYPE_MAX;
}

void AT_CmdBaseRegister(AT_DevInit init, AT_SendData send, AT_RevData rev, AT_GetCurTicks getticks)
{
    if(NULL == init || NULL == send || NULL == rev || NULL == getticks)
    {
        return ;
    }
    at_cmd_maininfo.getticks = getticks;
    at_cmd_maininfo.msgqueue_readindex = 0;
    at_cmd_maininfo.msgqueue_writeindex = 0;
    at_cmd_maininfo.msgqueue_handleindex = -1;
    at_cmd_maininfo.rev = rev;
    at_cmd_maininfo.send = send;
    return;
}



int AT_CmdBaseSendWithConfirmReply(char *cmdstr, char *responseok, char *responseerr, AT_ResponseCallback cb, int mstimeout, void *data)
{
    int ret = 0;
    if(NULL == cmdstr || MSGQUEUE_ISFULL)
         return -1;
    AT_CmdBaseClearElement(at_cmd_maininfo.msgqueue_writeindex);
    AT_CMD_Element *curWriteElement = &at_cmd_msgqueue[at_cmd_maininfo.msgqueue_writeindex];
    curWriteElement->cb = cb;
    curWriteElement->mstimeout = mstimeout;
    curWriteElement->responseerr = AT_CmdBaseDeepcopy(responseerr);
    curWriteElement->responseok = AT_CmdBaseDeepcopy(responseok);
    curWriteElement->senddata = AT_CmdBaseDeepcopy(cmdstr);
    curWriteElement->msgtype = AT_CMD_MSG_TYPE_CONFIRMREPLY;
    curWriteElement->data = data;
    MSGQUEUE_INDEX_INC(at_cmd_maininfo.msgqueue_writeindex);
    return ret;
}


int AT_CmdBaseSendWithUnConfirmReply(char *cmdstr,  AT_ResponseCallback cb, int mstimeout, void *data)
{
    int ret = 0;
    if(NULL == cmdstr || MSGQUEUE_ISFULL)
         return -1;
    AT_CmdBaseClearElement(at_cmd_maininfo.msgqueue_writeindex);
    AT_CMD_Element *curWriteElement = &at_cmd_msgqueue[at_cmd_maininfo.msgqueue_writeindex];
    curWriteElement->cb = cb;
    curWriteElement->senddata = AT_CmdBaseDeepcopy(cmdstr);
    curWriteElement->mstimeout = mstimeout;
    curWriteElement->msgtype = AT_CMD_MSG_TYPE_UNCONFIRMREPLY;
    curWriteElement->data = data;
    MSGQUEUE_INDEX_INC(at_cmd_maininfo.msgqueue_writeindex);
    return ret;
}


int AT_CmdBaseProcess()
{
   int ret = 0;
   char startHandlenextindex = 0;
   if(MSGQUEUE_ISEMPTY)
   {
       return 0;
   }
       
   AT_CMD_Element *curReadElement = &at_cmd_msgqueue[at_cmd_maininfo.msgqueue_readindex];
   if(at_cmd_maininfo.msgqueue_handleindex != at_cmd_maininfo.msgqueue_readindex) //正在处理的元素与当前的读索引不同时才发送下一个
   {
       at_cmd_maininfo.rev(at_cmd_maininfo.Revbuf, AT_CMD_REVBUF_MAX_SIZE);
       at_cmd_maininfo.msgqueue_handleindex = at_cmd_maininfo.msgqueue_readindex;
       at_cmd_maininfo.send(curReadElement->senddata, strlen(curReadElement->senddata));
       memset(at_cmd_maininfo.Revbuf, 0, sizeof(at_cmd_maininfo.Revbuf));
       at_cmd_maininfo.RevbufValidlen = 0;
       at_cmd_maininfo.cmdTimeoutticks = at_cmd_maininfo.getticks() + curReadElement->mstimeout;
   }

   ret = at_cmd_maininfo.rev(at_cmd_maininfo.Revbuf + at_cmd_maininfo.RevbufValidlen,
   AT_CMD_REVBUF_MAX_SIZE-at_cmd_maininfo.RevbufValidlen-1);
   if(ret > 0)
       at_cmd_maininfo.RevbufValidlen += ret;
   if(AT_CMD_MSG_TYPE_CONFIRMREPLY == curReadElement->msgtype)
   {
       if(strstr( at_cmd_maininfo.Revbuf, curReadElement->responseok) != NULL && at_cmd_maininfo.RevbufValidlen > 0)
       {
           curReadElement->cb(at_cmd_maininfo.Revbuf, AT_CMD_STATUS_OK, curReadElement->data);
           startHandlenextindex = 1;
       }
       else if(strstr( at_cmd_maininfo.Revbuf, curReadElement->responseerr) != NULL && at_cmd_maininfo.RevbufValidlen > 0)
       {
           curReadElement->cb(at_cmd_maininfo.Revbuf, AT_CMD_STATUS_ERROR, curReadElement->data);
           startHandlenextindex = 1;
       }
       else if(at_cmd_maininfo.getticks() >= at_cmd_maininfo.cmdTimeoutticks) //超时
       {
           
           curReadElement->cb(at_cmd_maininfo.Revbuf, AT_CMD_STATUS_OUTTIME, curReadElement->data);
           startHandlenextindex = 1;
       }
       else if(at_cmd_maininfo.RevbufValidlen  >= AT_CMD_REVBUF_MAX_SIZE - 1) //超过接收缓冲区大小
       {
           curReadElement->cb(at_cmd_maininfo.Revbuf, AT_CMD_STATUS_DATA_OVERFLOW, curReadElement->data);
           startHandlenextindex = 1;
       }

   }
   else if(AT_CMD_MSG_TYPE_UNCONFIRMREPLY == curReadElement->msgtype)
   {
       if(at_cmd_maininfo.RevbufValidlen > 0 && ret == 0) //当之前有数据接收后面出现未读取到数据时，进行一个超时增加处理
       {
           if(at_cmd_maininfo.getticks()  <=  at_cmd_maininfo.cmdTimeoutticks) //必须要在第一次超时内
              at_cmd_maininfo.cmdTimeoutticks = at_cmd_maininfo.getticks() + curReadElement->mstimeout;
       }
       else if(at_cmd_maininfo.RevbufValidlen > 0 && at_cmd_maininfo.getticks() > at_cmd_maininfo.cmdTimeoutticks) //超时但接收到数据
       {
           curReadElement->cb(at_cmd_maininfo.Revbuf, AT_CMD_STATUS_OK, curReadElement->data);
           startHandlenextindex = 1;
       }
       else if(at_cmd_maininfo.RevbufValidlen == 0 && at_cmd_maininfo.getticks() > at_cmd_maininfo.cmdTimeoutticks) //超时且未获取到数据
       {
           curReadElement->cb(at_cmd_maininfo.Revbuf, AT_CMD_STATUS_OUTTIME, curReadElement->data);
           startHandlenextindex = 1;
       }
       else if(at_cmd_maininfo.RevbufValidlen  >= AT_CMD_REVBUF_MAX_SIZE - 1) //超过接收缓冲区大小
       {
           curReadElement->cb(at_cmd_maininfo.Revbuf, AT_CMD_STATUS_DATA_OVERFLOW, curReadElement->data);
           startHandlenextindex = 1;
       }

   }

   //开始处理下一条命令
   if(1 == startHandlenextindex)
   {
        AT_CmdBaseClearElement(at_cmd_maininfo.msgqueue_readindex); //清理缓冲数据
        MSGQUEUE_INDEX_INC(at_cmd_maininfo.msgqueue_readindex);
   }
   return 0;
}